package com.lst.api.service.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.lst.api.constant.ContractConstants;
import com.lst.api.constant.DeleteEnum;
import com.lst.api.constant.OrderStatusEnum;
import com.lst.api.entity.LoanType;
import com.lst.api.entity.Order;
import com.lst.api.entity.OrderContract;
import com.lst.api.entity.PersonInfo;
import com.lst.api.entity.Product;
import com.lst.api.exception.RequestParamErrorException;
import com.lst.api.mapper.OrderContractMapper;
import com.lst.api.properties.FileProperties;
import com.lst.api.service.IFileUploadService;
import com.lst.api.service.IOrderContractService;
import com.lst.api.utils.WordUtil;
import com.lst.api.vo.OrderContractVo;
import com.lst.tools.basics.utils.DateUtils;
import com.lst.tools.basics.utils.RandomUtils;
import com.lst.tools.basics.utils.StringHelper;
import com.lst.tools.mybatis.service.impl.BaseService;

/**
 * 订单合同表业务层实现
 *
 * @author Frank
 * @date 2020-02-05 23:28:26
 * @version: V1.0
 */
@Service
public class OrderContractService extends BaseService<OrderContractMapper, OrderContract> implements IOrderContractService {

    @Autowired
    private ProductService productService;
    @Autowired
    private PersonInfoService personInfoService;
    @Autowired
    private LoanTypeService loanTypeService;
    @Autowired
    private OrderService orderService;
    @Autowired
    private IFileUploadService fileUploadService;
    @Autowired
    private FileProperties fileProperties;


    @Override
    public OrderContract saveOrderContract(MultipartFile signFile, OrderContractVo ocVo, long userId) throws Exception {
        if (ocVo == null) {
            throw new RequestParamErrorException("接收参数不能为空！");
        }
        ocVo.check();
        if (signFile == null || signFile.isEmpty()) {
            throw new RequestParamErrorException("签名文件不能为空！");
        }

//        checkExistApplying(ocVo);

        OrderContract ocItem = new OrderContract();
        BeanUtils.copyProperties(ocVo, ocItem);
        ocItem.setPromoUserId(userId);

        //合同参数
        Map<String, Object> contractParams = new HashMap<>();
        InputStream inputStream = signFile.getInputStream();
        setContractInfo(ocVo, contractParams, inputStream);
        setProductInfo(ocVo, contractParams);
        setPersonInfo(ocVo, ocItem, contractParams);
        setLoanType(ocVo, ocItem, contractParams);

        //生成合同文件
        String contractUrl = createContractFile(contractParams, userId);
        if (StringUtils.isBlank(contractUrl)) {
            throw new RequestParamErrorException("合同文件创建失败！");
        }
        ocItem.setContractUrl(contractUrl);

        Order order = new Order(ocItem);
        orderService.save(order);
        ocItem.setOrderId(order.getId());

        this.save(ocItem);
        return ocItem;
    }
    
	/**
     * 检查是否有正在申请的相同产品
     *
     * @param ocVo
     */
    public void checkExistApplying(OrderContractVo ocVo) {
        QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(Order.APPLY_NO, ocVo.getApplyNo())
                .eq(Order.PRODUCT_ID, ocVo.getProductId())
                .in(Order.ORDER_STATUS, OrderStatusEnum.ORDER_SUBMITTED.getKey(), OrderStatusEnum.LOAN_APPLYING.getKey())
                .eq(Order.IS_DELETE, DeleteEnum.DELETE_NO.getKey());
        List<Order> orderList = orderService.list(queryWrapper);
        if (CollectionUtils.isNotEmpty(orderList)) {
            throw new RequestParamErrorException("该客户已经存在正在申请此产品的订单！");
        }
    }

    /**
     * 设置合同信息
     *
     * @param ocVo
     * @param contractParams
     */
    public void setContractInfo(OrderContractVo ocVo, Map<String, Object> contractParams, InputStream inputStream) {
        Map<String, Object> header = new HashMap<String, Object>();
        header.put(ContractConstants.SIGN_WIDTH_NAME, 100);
        header.put(ContractConstants.SIGN_HEIGHT_NAME, 100);
        header.put(ContractConstants.SIGN_TYPE_NAME, ContractConstants.SIGN_IMAGE_TYPE);
        header.put(ContractConstants.SIGN_FIS_NAME, inputStream);
        contractParams.put(ContractConstants.SIGN, header);

        contractParams.put(ContractConstants.SERVICE_FEE, String.valueOf(ocVo.getServiceFee()));
        contractParams.put(ContractConstants.GUARANTEE_FEE, String.valueOf(ocVo.getGuaranteeFee()));
        contractParams.put(ContractConstants.ACC_MANAGE_FEE, String.valueOf(ocVo.getAccountManagementFee()));
        contractParams.put(ContractConstants.RISK_GUARANTEE_FEE, String.valueOf(ocVo.getRiskGuaranteeFee()));
        contractParams.put(ContractConstants.CHANNEL_AGENT_FEE, String.valueOf(ocVo.getChannelAgentFee()));
        contractParams.put(ContractConstants.INVOICE_RATE_FEE, String.valueOf(ocVo.getInvoiceRate()));
        contractParams.put(ContractConstants.INFO_FEE, String.valueOf(ocVo.getInformationFee()));
        contractParams.put(ContractConstants.ADVANCE_FEE, String.valueOf(ocVo.getAdvanceFee()));
        contractParams.put(ContractConstants.PREPAYMENT_FEE, String.valueOf(ocVo.getPrepaymentFee()));
        contractParams.put(ContractConstants.MORTGAGE_REGISTRANTION_FEE, String.valueOf(ocVo.getMortgageRegistrationQueryFee()));
        contractParams.put(ContractConstants.MORTGAGE_EMERGENCY_FEE, String.valueOf(ocVo.getMortgageRegistrationQueryFee()));
        contractParams.put(ContractConstants.RECEIVE_ADVANCE_MONEY, String.valueOf(ocVo.getReceiveAdvanceMoney()));
        contractParams.put(ContractConstants.REMARK, StringHelper.getObjectValue(ocVo.getRemark()));
        contractParams.put(ContractConstants.SIGN_DATE, DateUtils.format(new Date(), DateUtils.DATE_FORMAT_11));//签署时间

    }

    /**
     * 设置产品名称
     *
     * @param ocVo
     * @param contractParams
     */
    public void setProductInfo(OrderContractVo ocVo, Map<String, Object> contractParams) {
        Product product = productService.getById(ocVo.getProductId());
        if (product == null) {
            throw new RequestParamErrorException(String.format("未找到对应的产品，产品ID：%s", ocVo.getProductId()));
        }
        contractParams.put(ContractConstants.PRODUCT_TITLE, product.getTitle());
        contractParams.put(ContractConstants.LOAN_AMOUNT, String.valueOf(product.getMaxQuota()));
    }

    /**
     * 设置客户个人信息
     *
     * @param ocVo
     * @param ocItem
     * @param contractParams
     */
    public void setPersonInfo(OrderContractVo ocVo, OrderContract ocItem, Map<String, Object> contractParams) {
        PersonInfo personInfo = personInfoService.getOneByApplyNo(ocVo.getApplyNo());
        if (personInfo == null) {
            throw new RequestParamErrorException(String.format("未找到对应的客户个人信息，申请编号：%s", ocVo.getApplyNo()));
        }
        ocItem.setIdCardNo(personInfo.getIdCardNo());
        ocItem.setName(personInfo.getName());

        contractParams.put(ContractConstants.ID_CARD_NO, personInfo.getIdCardNo());
        contractParams.put(ContractConstants.NAME, personInfo.getName());
    }

    /**
     * 设置贷款种类信息
     *
     * @param ocVo
     * @param ocItem
     * @param contractParams
     */
    public void setLoanType(OrderContractVo ocVo, OrderContract ocItem, Map<String, Object> contractParams) {
    	String[] loanTypeIdArr = ocVo.getLoanTypeIds().split(",");
        List<Long> loanTypeIdList = new ArrayList<>();
        for (String loanTypeId : loanTypeIdArr) {
            loanTypeIdList.add(Long.parseLong(loanTypeId));
        }
        
        if (CollectionUtils.isNotEmpty(loanTypeIdList)) {
            List<LoanType> loanTypeList = (List<LoanType>) loanTypeService.listByIds(loanTypeIdList);
            if (CollectionUtils.isEmpty(loanTypeList) || loanTypeIdList.size() != loanTypeList.size()) {
                throw new RequestParamErrorException(String.format("贷款种类信息未能完全匹配，贷款种类ID：%s", ocVo.getLoanTypeIds()));
            } else {
                List<String> loanTypeNames = new ArrayList<>();
                loanTypeList.stream().forEach(
                        item -> {
                            if (StringUtils.isNotBlank(item.getTitle())) {
                                loanTypeNames.add(item.getTitle());
                            }
                        }
                );
                if (CollectionUtils.isNotEmpty(loanTypeNames)) {
                    ocItem.setLoanType(JSON.toJSONString(loanTypeNames));
                    contractParams.put(ContractConstants.LOAN_TYPE, StringUtils.join(loanTypeNames, ","));
                } else {
                    throw new RequestParamErrorException(String.format("未找到对应的贷款种类信息，贷款种类ID：%s", ocVo.getLoanTypeIds()));
                }
            }
        } else {
            throw new RequestParamErrorException(String.format("未找到对应的贷款种类信息，贷款种类ID：%s", ocVo.getLoanTypeIds()));
        }
    }

    /**
     * 生成合同文件
     *
     * @param param
     * @return
     * @throws Exception
     * @throws FileNotFoundException
     */
    public String createContractFile(Map<String, Object> param, long userId) throws Exception {
    	
        String filePath = WordUtil.replaceAndGenerateWord(fileProperties.getContractTemplatePath(), fileProperties.getTempPath(), param);
        
        if (StringUtils.isNotBlank(filePath)) {
        	File file = new File(filePath);
        	if(!file.exists() || !file.isFile() || file.length() <= 0) {
        		throw new RequestParamErrorException("合同文件生成失败！");
        	}
        	String uploadResult = fileUploadService.fileUpload(userId, ContractConstants.CONTRACT_FOLDER, RandomUtils.createNonceStr(), ContractConstants.CONTRACT_FILE_TYPE, new FileInputStream(file));
            file.delete();
            return uploadResult;
        }else {
        	throw new RequestParamErrorException("合同文件生成失败！");
        }
    }
    
}